package com.simple.util.base;

import org.apache.commons.lang3.ArrayUtils;

/**
 * @program: simple_tools
 * @description:
 * @author: Mr.chen
 * @create: 2020-06-08 16:01
 **/
public class ByteUtil {

    // 十六进制下数字到字符的映射数组
    private final static String[] hexDigits = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" };

    /**
     * 将一个字节转化成十六进制形式的字符串
     *
     * @param b
     * @return
     */
    private static String byteToHex(byte b) {
        int n = b;
        if (n < 0) {
            n = 256 + n;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    /**
     * 轮换字节数组为十六进制字符串
     *
     * @param b
     *            字节数组
     * @return 十六进制字符串
     */
    public static String byteArrayToHexString(byte[] b) {
        StringBuffer resultSb = new StringBuffer();
        for (byte element : b) {
            resultSb.append(ByteUtil.byteToHex(element));
        }
        return resultSb.toString();
    }

    /**
     * 二行制转字符串
     *
     * @param b
     * @return
     */
    public static String byteArrayToHex(byte[] b) {// 一个字节的数，
        // 转成16进制字符串
        String hs = "";
        String stmp = "";
        for (byte element : b) {
            // 整数转成十六进制表示
            stmp = (java.lang.Integer.toHexString(element & 0XFF));
            if (stmp.length() == 1) {
                hs = hs + "0" + stmp;
            } else {
                hs = hs + stmp;
            }
        }
        return hs.toUpperCase();// 转成大写
    }

    /**
     * 填充至指定长度的倍数
     *
     * @param b
     * @param length
     * @return
     */
    public static byte[] fileByte(byte[] b, int length) {
        int pad = b.length % length;
        byte[] appendByte = new byte[length - pad];
        for (int i = 0; i < (length - pad); i++) {
            appendByte[i] = Byte.MAX_VALUE;
        }
        return ArrayUtils.addAll(b, appendByte);
    }

    /**
     * 二进制转文本
     *
     * @param b
     * @return
     */
    public static String byte2Str(byte[] b) {
        String result = "";
        for (Byte bytes : b) {
            result += (char) bytes.intValue();
        }
        return result;
    }

    /**
     * 从16进制字符串转换过来
     *
     * @param sc
     * @return
     */
    public static byte[] fromHex(byte[] sc) {
        byte[] res = new byte[sc.length / 2];
        for (int i = 0; i < sc.length; i++) {
            byte c1 = (byte) ((sc[i] - 48) < 17 ? sc[i] - 48 : sc[i] - 55);
            i++;
            byte c2 = (byte) ((sc[i] - 48) < 17 ? sc[i] - 48 : sc[i] - 55);
            res[i / 2] = (byte) ((c1 * 16) + c2);
        }
        return res;
    }

    /**
     *
     * @param hex
     * @return
     */
    public static byte[] fromHexString(String hex) {
        return fromHex(hex.getBytes());
    }

    /**
     *
     * @param in
     * @return
     */
    public static String decode(String in) {
        return new String(fromHex(in.getBytes()));
    }

    /**
     *
     * @param abyte0
     * @param abyte1
     * @return
     */
    public static byte[] Append(byte[] abyte0, byte[] abyte1) {
        return ByteUtil.Append(abyte0, abyte1, abyte0.length);
    }

    /**
     *
     * @param abyte0
     * @param abyte1
     * @param startIndex
     * @return
     */
    public static byte[] Append(byte[] abyte0, byte[] abyte1, int startIndex) {
        return ByteUtil.Append(abyte0, abyte1, startIndex, 0);
    }

    /**
     *
     * @param byte0
     * @param byte1
     * @param startIndex
     * @param length
     * @return
     */
    public static byte[] Append(byte[] byte0, byte[] byte1, int startIndex, int length) {
        int rl = 0;
        if ((startIndex > -1) && (byte0 != null) && (startIndex < byte0.length)) {
            rl = startIndex;
        } else if (byte0 != null) {
            rl = byte0.length;// Math.min(startIndex, byte0.length);
        }
        int bl = 0;
        if ((length > 0) && (byte1 != null) && (length < byte1.length)) {
            bl = length;
        } else if (byte1 != null) {
            bl = byte1.length;
        }

        if ((rl + bl) > 0 && byte0 != null && byte1 != null) {
            byte[] result = new byte[rl + bl];
            int j = 0;
            for (int i = 0; i < rl; i++, j++) {
                result[j] = byte0[i];
            }
            for (int i = 0; i < bl; i++, j++) {
                result[j] = byte1[i];
            }
            return result;
        }
        return null;
    }

    /**
     *
     * @param byte0
     * @param startIndex
     * @return
     */
    public static byte[] Read(byte[] byte0, int startIndex) {
        return ByteUtil.Read(byte0, startIndex, byte0.length);
    }

    /**
     *
     * @param byte0
     * @param startIndex
     * @param length
     * @return
     */
    public static byte[] Read(byte[] byte0, int startIndex, int length) {
        int rl = Math.min(length, byte0.length - startIndex);
        byte[] result = new byte[rl];
        for (int i = 0, j = startIndex; i < rl; i++, j++) {
            result[i] = byte0[j];
        }
        return result;
    }

    /**
     *
     * @param b
     * @return
     */
    public static long toLong(byte... b) {
        if (b.length > 8) {
            return 0;
        }

        int shift = 0;
        long result = 0;
        for (int i = b.length - 1; i >= 0; i--) {
            result = result + ((b[i] & 0xFF) << shift);
            shift += 8;
        }
        return result;
    }

    /**
     *
     * @param b
     * @return
     */
    public static short toShort(byte... b) {
        return (short) toLong(b);
    }

    /**
     *
     * @param l
     * @param length
     * @return
     */
    private static byte[] numberToByte(long l, int length) {
        byte[] bts = new byte[length];
        for (int i = 0; i < length; i++) {
            bts[i] = (byte) (l >> ((length - i - 1) * 8));
        }
        return bts;
    }

    /**
     *
     * @param i
     * @return
     */
    public static byte[] shortToByte(short i) {
        return numberToByte(i, 2);
    }

    /**
     *
     * @param i
     * @return
     */
    public static byte[] intToByte(int i) {
        return numberToByte(i, 4);
    }

    /**
     *
     * @param i
     * @return
     */
    public static byte[] longToByte(long i) {
        return numberToByte(i, 8);
    }
}
